--- 战斗主类
---
--- @class AbstractFighterAttributeManager
AbstractFighterAttributeManager = ClientFight.CreateClass("AbstractFighterAttributeManager")
local this = AbstractFighterAttributeManager

--- @public
--- @return AbstractFighterAttributeManager
--rotected static Logger log = LoggerFactory.getLogger(AbstractFighterAttributeManager.class);
-- 怪物属性计算器
---@type table<CalculatorTypeEnum, IAttributeCalculator>
this.fighterCalculators = {};
---@type table<CalculatorTypeEnum, IAttributeCalculator>
this.teamFighterCalculators = {};
function AbstractFighterAttributeManager.ctor()
end
function AbstractFighterAttributeManager.registerFighterAttrCal(calculator)
    this.fighterCalculators[calculator:getType()] = calculator;
end
function AbstractFighterAttributeManager.registerTeamFighterAttrCal(calculator)
    this.teamFighterCalculators[calculator:getType()] = calculator;
end

--[[
* 初始化战斗者属性
*
* @param fighter
*/]]
function AbstractFighterAttributeManager.initFighterAttribute(fight, fighter)
    -- 遍历所有计算器设置到玩家身上
    for i, calculator in pairs(this.fighterCalculators) do
        local attribute = ClientFight.BaseAttribute.New();
        local state = BaseState.New();
        local sign = BaseSign.New();
        calculator:countAttribute(fight, fighter, attribute, state, sign);
        fighter.attributeCalculators[calculator:getType()] = attribute;
        fighter.stateCalculators[calculator:getType()] = state;
        fighter.signCalculators[calculator:getType()] = sign;
    end
    this.reset(fighter, true);
    -- 战斗服计算属性之后,, 把战前属性记录下来
    local baseAttribute = ClientFight.BaseAttribute.New(fighter.totalAttribute);
    baseAttribute.attributes[FighterAttributeEnum.ATK_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.BASE_ATK_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_ATK_PER.id] = nil;

    baseAttribute.attributes[FighterAttributeEnum.BASE_DEF_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_DEF_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.DEF_PER.id] = nil;

    baseAttribute.attributes[FighterAttributeEnum.BASE_HP_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_HP_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.HP_PER.id] = nil;

    fighter.attributeCalculators[CalculatorTypeEnum.BEFORE_FIGHT] = baseAttribute;
    fighter.totalAttribute = (ClientFight.BaseAttribute.New(baseAttribute));
end

function AbstractFighterAttributeManager.initTeamFighterAttribute(fight, fighter)
    -- 遍历所有计算器设置到玩家身上
    for i, calculator in pairs(this.teamFighterCalculators) do

        local attribute = ClientFight.BaseAttribute.New();
        local state = BaseState.New();
        local sign = BaseSign.New();
        calculator:countAttribute(fight, fighter, attribute, state, sign);
        fighter.attributeCalculators[calculator:getType()] = attribute;
        fighter.stateCalculators[calculator:getType()] = state;
        fighter.signCalculators[calculator:getType()] = sign;
    end
    reset(fighter, true);
    -- 战斗服计算属性之后,, 把战前属性记录下来
    local baseAttribute = ClientFight.BaseAttribute.New(fighter.totalAttribute);
    baseAttribute.attributes[FighterAttributeEnum.ATK_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.BASE_ATK_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_ATK_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.BASE_DEF_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_DEF_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.DEF_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.BASE_HP_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.EQUIP_HP_PER.id] = nil;
    baseAttribute.attributes[FighterAttributeEnum.HP_PER.id] = nil;

    fighter.attributeCalculators[CalculatorTypeEnum.BEFORE_FIGHT] = baseAttribute;
    fighter.totalAttribute = ClientFight.BaseAttribute.New(baseAttribute);
end

--[[
* 设置战斗者属性
* @param fighter
* @return 返回战斗者最新属性的副本
*
*]]
function AbstractFighterAttributeManager.reset(fighter, beforFight)
    local totalAttribute = fighter.totalAttribute;
    if (totalAttribute == nil) then
        totalAttribute = ClientFight.BaseAttribute.New();
    end
    local totalState = fighter.totalState;
    if (totalState == nil) then
        totalState = BaseState.New();
    end
    local totalSign = fighter.totalSign;
    if (totalSign == nil) then
        totalSign = BaseSign.New();
    end

    -- 重新赋值
    fighter.totalAttribute.attributes = {};
    totalState.state = 0;
    totalSign.signs = {};

    this.countTotalState(fighter, totalState);
    this.countTotalSign(fighter, totalSign);

    fighter.totalState = totalState;
    fighter.totalSign = totalSign;

    this.countTotalAttribute(fighter,  fighter.totalAttribute, beforFight);
    fighter.totalAttribute = totalAttribute;

    local hp = fighter.totalAttribute.attributes[FighterAttributeEnum.HP.id];
    if (fighter.hp > hp) then
        fighter.hp = hp;
    end
end

--[[
* 计算战斗者总属性
*
* @param fighter
*/]]
function AbstractFighterAttributeManager.countTotalAttribute(fighter, totalAttribute, beforFight)
    -- 基础属性
    local baseAttribute = BaseAttribute.empty;
    -- 装备属性
    local equipAttribute = BaseAttribute.empty;
    if (beforFight) then
        --战斗中,只计算buff和战前属性
        -- 基础属性
        baseAttribute = this.getAttribute(fighter, CalculatorTypeEnum.BASE);
        -- 装备属性
        equipAttribute = this.getAttribute(fighter, CalculatorTypeEnum.EQUIP);
    end

    local otherAttribute = ClientFight.BaseAttribute.New();
    for i, calculatortype in pairs(CalculatorTypeEnum:values()) do

        if (calculatortype ~= CalculatorTypeEnum.BASE and calculatortype ~= CalculatorTypeEnum.EQUIP) then
            local is = true;
            if (not beforFight) then
                --战斗中,只计算buff和战前属性
                if (calculatortype ~= CalculatorTypeEnum.BUFF and calculatortype ~= CalculatorTypeEnum.BEFORE_FIGHT) then
                    is = false;
                end
            else
                if (calculatortype == CalculatorTypeEnum.BEFORE_FIGHT or calculatortype == CalculatorTypeEnum.BUFF) then

                    is = false;
                end
            end
            if is then

                -- 获取该资源线的属性
                local attr = this.getAttribute(fighter, calculatortype);
                local add = true;
                if (calculatortype == CalculatorTypeEnum.BUFF) then
                    if (fighter.totalSign.signs[FighterSignEnum.TAG_1002]) then
                        add = false;--有1002标记, buff属性只减不加
                    end
                end
                this.add(otherAttribute, attr, add);
            end
        end
    end
    local beforFigthAttr = this.getAttribute(fighter, CalculatorTypeEnum.BEFORE_FIGHT);
    local o = fighter.parametersByObject[BuffEffect92055100.BuffEffect92055100];
    local limitAttr = nil;
    if (o ~= nil) then
        limitAttr = o;
    end
    -- 计算总属性
    for i, attribute in pairs(FighterAttributeEnum:values()) do

        local baseValue = this.getMapValue(baseAttribute.attributes, attribute.id);
        local equipValue = this.getMapValue(equipAttribute.attributes, attribute.id);
        local otherValue = this.getMapValue(otherAttribute.attributes, attribute.id);
        local value = 0;
        -- 攻击属性
        if (attribute.id == FighterAttributeEnum.ATK.id or attribute.id == FighterAttributeEnum.DEF.id
                or attribute.id == FighterAttributeEnum.HP.id) then
            local basePerAttribute = nil;
            local equipPerAttribute = nil;
            local totalPerAttribute = nil;
            if (attribute.id == FighterAttributeEnum.ATK.id) then
                basePerAttribute = FighterAttributeEnum.BASE_ATK_PER;
                equipPerAttribute = FighterAttributeEnum.EQUIP_ATK_PER;
                totalPerAttribute = FighterAttributeEnum.ATK_PER;
            elseif (attribute.id == FighterAttributeEnum.DEF.id) then
                basePerAttribute = FighterAttributeEnum.BASE_DEF_PER;
                equipPerAttribute = FighterAttributeEnum.EQUIP_DEF_PER;
                totalPerAttribute = FighterAttributeEnum.DEF_PER;
            elseif (attribute.id == FighterAttributeEnum.HP.id) then
                basePerAttribute = FighterAttributeEnum.BASE_HP_PER;
                equipPerAttribute = FighterAttributeEnum.EQUIP_HP_PER;
                totalPerAttribute = FighterAttributeEnum.HP_PER;
            end

            local basePer = this.getMapValue(baseAttribute.attributes, basePerAttribute.id);
            local equipBasePer = this.getMapValue(equipAttribute.attributes, basePerAttribute.id);
            local otherBasePer = this.getMapValue(otherAttribute.attributes, basePerAttribute.id);

            local equipPer = this.getMapValue(equipAttribute.attributes, equipPerAttribute.id);
            local baseEquipPer = this.getMapValue(baseAttribute.attributes, equipPerAttribute.id);
            local otherEquipPer = this.getMapValue(otherAttribute.attributes, equipPerAttribute.id);

            local totalPer = this.getMapValue(baseAttribute.attributes, totalPerAttribute.id);
            local equipTotalPer = this.getMapValue(equipAttribute.attributes, totalPerAttribute.id);
            local otherTotalPer = this.getMapValue(otherAttribute.attributes, totalPerAttribute.id);

            value = ((baseValue * (Global.TEN_THOUSANDTH + basePer + equipBasePer + otherBasePer) / Global.TEN_THOUSANDTH
                    + equipValue * (Global.TEN_THOUSANDTH + equipPer + baseEquipPer + otherEquipPer) / Global.TEN_THOUSANDTH
                    + otherValue) * (Global.TEN_THOUSANDTH + totalPer + equipTotalPer + otherTotalPer) / Global.TEN_THOUSANDTH);
            -- 其他属性
        else
            value = baseValue + equipValue + otherValue;
        end
        if (limitAttr ~= null and table.contains(limitAttr, attribute)) then
            --被限制了属性
            local beforAttValue = beforFigthAttr.attributes[attribute.id] or 0;
            if (value > beforAttValue) then
                value = beforAttValue;
            end
        end
        totalAttribute.attributes[attribute.id] = value;
    end
end

--[[
* 计算战斗者总属性
*
* @param fighter
*/]]
function AbstractFighterAttributeManager.countTotalState(fighter, totalState)
    for i, calculatortype in pairs(CalculatorTypeEnum:values()) do

        -- 获取该资源线的属性
        local state = this.getState(fighter, calculatortype);
        local value = bit.bor(state.state, totalState.state);
        totalState.state = value;
    end
end

--[[
* 计算战斗者总标记
*
* @param fighter
*/]]
function AbstractFighterAttributeManager.countTotalSign(fighter, totalSign)
    for i, calculatortype in pairs(CalculatorTypeEnum:values()) do

        -- 获取该资源线的属性
        local sign = this.getSign(fighter, calculatortype);
        totalSign.signs = sign.signs;
    end
end

--[[
* 获取战斗者属性
*
* @param fighter
* @param type    类型
*/]]
function AbstractFighterAttributeManager.getAttribute(fighter, type)
    local temp =fighter.attributes[type] or fighter.attributes[tostring(type)]
    local attribute = clone(temp);
    if (attribute ~= nil) then
        return attribute;
    end
    attribute = fighter.attributeCalculators[type];
    if (attribute == nil) then
        attribute = ClientFight.BaseAttribute.New();
        fighter.attributeCalculators[type] = attribute;
    end
    return clone(attribute);
end

--[[
* 获取战斗者状态
*
* @param fighter
* @param type    类型
*/]]
function AbstractFighterAttributeManager.getState(fighter, type)
    local state = fighter.stateCalculators[type];
    if (state == nil) then
        state = BaseState.New();
        fighter.stateCalculators[type] = state;
    end
    return state;
end

--[[
* 获取战斗者标记
*
* @param fighter
* @param type    类型
*/]]
function AbstractFighterAttributeManager.getSign(fighter, type)
    if (not fighter.signCalculators[type]) then
        local sign = BaseSign.New();
        if not fighter.signCalculators[type] then
            fighter.signCalculators[type] = sign;
        end
    end
    return fighter.signCalculators[type];
end

--[[
* 计算玩家属性
*
* @param fighter
* @param type    类型
*/]]
function AbstractFighterAttributeManager.countFighterAttribute(fight, fighter, type)
    local attributeCalculator = fighterCalculators[type];
    if (attributeCalculator == nil
            or not fighter.attributeCalculators[attributeCalculator:getType()]) then
        return ;
    end
    local attr = this.getAttribute(fighter, type);

    local state = this.getState(fighter, type);

    local sign = this.getSign(fighter, type);
    -- 重新赋值
    attr.attributes = { };
    state.state = 0;
    sign.signs = {};

    attributeCalculator:countAttribute(fight, fighter, attr, state, sign);

    -- 设置属性
    reset(fighter, false);
end

--[[
* 属性相加
*
* @param target
* @param source
*/]]
function AbstractFighterAttributeManager.add(target, source, add)
    local attributes = source.attributes;
    if (attributes == nil) then
        return ;
    end

    local entries = attributes;
    for key, value in pairs(entries) do
        if type(key) == "number" then
            if (not add and value > 0) then
                value = 0;
            end
            local oldValue = getMapValue(target.attributes, key);
            target.attributes[key] = oldValue + value;
        end
    end
    --		for (FighterAttributeEnum type : FighterAttributeEnum.values()) {--没必要每次都是循环所有的
    --			long value = 0;
    --			value += getMapValue(targetattributes, type.getId());
    --			value += getMapValue(sourceattributes, type.getId());
    --			targetattributes.put(type.getId(), value);
    --		}
end

function AbstractFighterAttributeManager.getMapValue(map, key)
    local temp =map[key] or map[tostring(key)];
    if temp  then
    else
        map[key] = 0;
        temp = 0;
    end
    return temp;
end;
